<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态光圈</title>
    <script src="./three.js"></script>
    <link rel="stylesheet" href="https://js.arcgis.com/4.18/esri/themes/light/main.css"/>
    <script src="https://js.arcgis.com/4.18/"></script>
</head>
<style>
    html, body, #mapContainer {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
    }
</style>
<body>
<div id="mapContainer"></div>
</body>
<script>
    require([
        "esri/Map","esri/views/SceneView","esri/views/3d/externalRenderers",
        'esri/geometry/support/webMercatorUtils',"esri/geometry/SpatialReference",
        "esri/geometry/Extent",'esri/layers/GraphicsLayer','esri/Graphic',
    ], function (Map, SceneView, externalRenderers, webMercatorUtils, SpatialReference,Extent,GraphicsLayer,Graphic) {

        let pointTemp = [117.28, 31.86];

        //初始化地图
        let map = new Map({
            basemap: "streets-navigation-vector",
            ground:'world-elevation'
        });

        //初始化场景
        let view = new SceneView({
            container: "mapContainer",
            map: map,
            viewingMode: "local",
            camera: {
                position: [117.27870319392615, 31.738730506030283, 9547.106932271272],
                fov: 55,
                heading: 359.99613521961805,
                tilt: 55.00000000000099
            }
        });

        //添加点图形
        view.graphics.add(new Graphic({
            geometry:{
                type:'point',
                longitude:pointTemp[0],
                latitude:pointTemp[1]
            },
            symbol:{
                type: "point-3d",  // autocasts as new PointSymbol3D()
                symbolLayers: [{
                    type: "icon",  // autocasts as new IconSymbol3DLayer()
                    size: 8,  // points
                    resource: { primitive: "circle" },
                    material: { color: "red" }
                }]
            }
        }))

        //将几何和材料整合成物体
        function transparentObject(geometry, material) {
            let obj = new THREE.Object3D();
            let mesh = new THREE.Mesh(geometry, material);
            mesh.material.side = THREE.BackSide; // back faces
            mesh.renderOrder = 0;
            obj.add(mesh);

            mesh = new THREE.Mesh(geometry, material.clone());
            mesh.material.side = THREE.FrontSide; // front faces
            mesh.renderOrder = 1;
            obj.add(mesh);
            return obj
        }

        const myRenderer = {
            view: view,

            renderer: null, // three.js 渲染器
            camera: null, // three.js 相机
            scene: null, // three.js 中的场景

            height: 100, // 高度
            offset: 0, // 偏移量

            setup: function (context) {
                //初始化渲染
                this.renderer = new THREE.WebGLRenderer({
                    context: context.gl, // 可用于将渲染器附加到已有的渲染环境(RenderingContext)中
                    premultipliedAlpha: false, // renderer是否假设颜色有 premultiplied alpha. 默认为true
                });

                this.renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比。通常用于避免HiDPI设备上绘图模糊
                this.renderer.setViewport(0, 0, view.width, view.height); // 视口大小设置

                // 防止Three.js清除ArcGIS JS API提供的缓冲区。
                this.renderer.autoClearDepth = false; // 定义renderer是否清除深度缓存
                this.renderer.autoClearStencil = false; // 定义renderer是否清除模板缓存
                this.renderer.autoClearColor = false; // 定义renderer是否清除颜色缓存

                // ArcGIS JS API渲染自定义离屏缓冲区，而不是默认的帧缓冲区。
                // 我们必须将这段代码注入到three.js运行时中，以便绑定这些缓冲区而不是默认的缓冲区。
                const originalSetRenderTarget = this.renderer.setRenderTarget.bind(
                    this.renderer
                );
                this.renderer.setRenderTarget = function (target) {
                    originalSetRenderTarget(target);
                    if (target == null) {
                        // 绑定外部渲染器应该渲染到的颜色和深度缓冲区
                        context.bindRenderTarget();
                    }
                };

                let renderPos = [];
                //将位置从给定的空间参考转换为内部渲染坐标系。
                externalRenderers.toRenderCoordinates(this.view, [pointTemp[0], pointTemp[1],0],0, SpatialReference.WGS84, renderPos, 0, 1);
                // 添加坐标轴辅助工具
                const axesHelper = new THREE.AxesHelper(10000000);
                this.scene.add(axesHelper);

                //---------------------------------------------------自定义开始------------------------------------------
                this.scene = new THREE.Scene(); // 场景
                this.camera = new THREE.PerspectiveCamera(); // 相机

                // 几何体
                const geometry = new THREE.CylinderGeometry(100, 100, 100, 500, 1, true);
                //偏移
                geometry.translate(0, 15, 0);
                // 纹理
                this.texture = new THREE.TextureLoader().load(
                    'img/saom.png'
                );
                this.texture.repeat.x = 2;
                //初始化材料
                const material = new THREE.MeshStandardMaterial({
                    opacity: 1,
                    transparent: true, // 必须设置为true,alphaMap才有效果
                    depthWrite: false, // 渲染此材质是否对深度缓冲区有任何影响
                    map: this.texture,
                });
                //将几何和材料整合成物体
                this.mesh = transparentObject(geometry, material);

                //物体旋转
                this.mesh.position.set(renderPos[0], renderPos[1], renderPos[2]);
                this.mesh.rotation.x= Math.PI/2;

                this.scene.add(this.mesh);
                this.mesh.scale.set(10, 10, 0); // 放大一点

                //初始化灯光
                let ambient = new THREE.AmbientLight(0xffffff, 1);
                ambient.position.set(0, 100, 0);
                this.scene.add(ambient);
                //---------------------------------------------------自定义结束------------------------------------------


                context.resetWebGLState();
            },
            render: function (context) {
                // 更新相机参数(使得地图和threejs中的物体保持同步)
                this.camera.position.set(context.camera.eye[0], context.camera.eye[1], context.camera.eye[2]);
                this.camera.up.set(context.camera.up[0], context.camera.up[1], context.camera.up[2]);
                this.camera.lookAt(
                    new THREE.Vector3(context.camera.center[0], context.camera.center[1], context.camera.center[2])
                );
                // 投影矩阵可以直接复制
                this.camera.projectionMatrix.fromArray(context.camera.projectionMatrix);


                //---------------------------------------------------自定义开始------------------------------------------
                // 更新 缩放,作用使圆圈大到一定程度重新开始
                this.mesh.scale.x += 0.06
                this.mesh.scale.z += 0.06
                if (this.mesh.scale.x > 10) {
                    this.mesh.scale.x = 1
                    this.mesh.scale.z = 1
                }
                //---------------------------------------------------自定义结束------------------------------------------


                // 绘制场景
                this.renderer.state.reset();
                this.renderer.render(this.scene, this.camera);

                // 请求重绘视图。
                externalRenderers.requestRender(view);
                // cleanup
                context.resetWebGLState();
            },
        };

        // 注册renderer
        externalRenderers.add(view, myRenderer);
    })
</script>
</html>
